/*
 * Created on Oct 20, 2005
 *
 */
package org.mushroomdb.security.jaas;

import java.io.IOException;
import java.security.Principal;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

import org.mushroomdb.exception.EvaluationEngineException;
import org.mushroomdb.interceptor.CompositeInterceptor;
import org.mushroomdb.interceptor.Interceptor;
import org.mushroomdb.interceptor.InterceptorService;
import org.mushroomdb.security.SecurityInterceptor;
import org.mushroomdb.security.SecurityService;
import org.mushroomdb.security.User;
import org.mushroomdb.service.ServiceManager;

/**
 * @author Matu
 *  
 */
public class MushroomLoginModule implements LoginModule {
    private Subject subject;

    private CallbackHandler callbackHandler;

    private boolean success;

    private String userName;

    /**
     * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject,
     *      javax.security.auth.callback.CallbackHandler, java.util.Map,
     *      java.util.Map)
     */
    public void initialize(Subject subject, CallbackHandler callbackHandler,
            Map sharedState, Map options) {
        this.subject = subject;
        this.callbackHandler = callbackHandler;
        this.success = false;
    }

    /**
     * @see javax.security.auth.spi.LoginModule#login()
     */
    public boolean login() throws LoginException {
        NameCallback nameCallback = new NameCallback("Username"); //$NON-NLS-1$
        PasswordCallback passwordCallback = new PasswordCallback(
                "Password", false); //$NON-NLS-1$

        try {
            this.callbackHandler.handle(new Callback[] { nameCallback,
                    passwordCallback });
        } catch (IOException e) {
            throw new LoginException("Error authenticating: " + e.getMessage()); //$NON-NLS-1$
        } catch (UnsupportedCallbackException e) {
            throw new LoginException("Error authenticating: " + e.getMessage()); //$NON-NLS-1$
        }

        //		 FIXME por Tom
        // Hay que hacer la consulta a la base
//        if (!"mushroom".equals(nameCallback.getName()) //$NON-NLS-1$
//        		|| !"badger".equals(new String(passwordCallback.getPassword()))) {
//        
//        	throw new FailedLoginException("Login is incorrect."); //$NON-NLS-1$
//        }
      
        
        if ("mushroom".equals(nameCallback.getName())){
            this.success = true;
            this.userName = nameCallback.getName();
            return true;
        }
        else if(!checkAuthentication(nameCallback.getName(), new String(passwordCallback.getPassword())))
            throw new FailedLoginException("Login is incorrect."); //$NON-NLS-1$
        // end FIXME

        this.success = true;
        this.userName = nameCallback.getName();
        return true;
    }

    private boolean checkAuthentication(String user, String password) {
        SecurityService service = (SecurityService) ServiceManager
                .getInstance().getService(SecurityService.class);
        SecurityInterceptor interceptor = getSecurityInterceptor();
        
        if(interceptor==null){
            //el servicio de seguridad no esta inicializado
            return true;
        }
        
        User usr = null;
        try {
            interceptor.setToken();
            usr = service.getUserByName(user);
            interceptor.removeToken();
        } catch (Throwable e) {
            e.printStackTrace();
            return false;
        }

        return password.equals(usr.getPassword());

    }

    /**
     * @see javax.security.auth.spi.LoginModule#commit()
     */
    public boolean commit() throws LoginException {

        /** Login failed */
        if (!this.success) {
            this.userName = null;
            return false;
        }

        /** Login success */
        Principal principal = new MushroomPrincipal(this.userName);
        this.subject.getPrincipals().add(principal);

        this.userName = null;
        return true;
    }

    /**
     * @see javax.security.auth.spi.LoginModule#abort()
     */
    public boolean abort() throws LoginException {
        this.userName = null;

        if (this.success) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * @see javax.security.auth.spi.LoginModule#logout()
     */
    public boolean logout() throws LoginException {
        Iterator iterator = this.subject.getPrincipals().iterator();
        while (iterator.hasNext()) {
            Object object = iterator.next();
            if (object instanceof MushroomPrincipal) {
                iterator.remove();
            }
        }
        return true;
    }
    
    private SecurityInterceptor getSecurityInterceptor() {
        InterceptorService interceptorService = InterceptorService.getInstance();
        CompositeInterceptor compositeInterceptor = (CompositeInterceptor) interceptorService.getInterceptor();
        List interceptors = compositeInterceptor.getInterceptors();
        Iterator iter = interceptors.iterator();
        
        while(iter.hasNext()){
            Interceptor interceptor =(Interceptor) iter.next();
            if(interceptor instanceof SecurityInterceptor){
                return (SecurityInterceptor)interceptor;
            }
        }
        return null;
    }
}
